/*
* Capsule
* Copyright (c) 2014-2016, Parallel Universe Software Co. All rights reserved.
*
* This program and the accompanying materials are licensed under the terms
* of the Eclipse Public License v1.0, available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package capsule;
import static java.util.Collections.unmodifiableMap;
import java.io.PrintStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
import org.eclipse.aether.AbstractForwardingRepositorySystemSession;
import org.eclipse.aether.ConfigurationProperties;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositoryException;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.collection.CollectRequest;
import org.eclipse.aether.collection.CollectResult;
import org.eclipse.aether.collection.DependencyCollectionException;
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.graph.DependencyFilter;
import org.eclipse.aether.graph.DependencyNode;
import org.eclipse.aether.graph.DependencyVisitor;
import org.eclipse.aether.graph.Exclusion;
import org.eclipse.aether.impl.DefaultServiceLocator;
import org.eclipse.aether.repository.Authentication;
import org.eclipse.aether.repository.AuthenticationSelector;
import org.eclipse.aether.repository.LocalRepository;
import org.eclipse.aether.repository.Proxy;
import org.eclipse.aether.repository.ProxySelector;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.repository.RepositoryPolicy;
import org.eclipse.aether.resolution.ArtifactResult;
import org.eclipse.aether.resolution.DependencyRequest;
import org.eclipse.aether.resolution.DependencyResolutionException;
import org.eclipse.aether.resolution.DependencyResult;
import org.eclipse.aether.resolution.VersionRangeRequest;
import org.eclipse.aether.resolution.VersionRangeResult;
import org.eclipse.aether.resolution.VersionRequest;
import org.eclipse.aether.resolution.VersionResult;
import org.eclipse.aether.util.artifact.ArtifactIdUtils;
import org.eclipse.aether.util.artifact.JavaScopes;
import org.eclipse.aether.util.graph.transformer.ConflictResolver;
import org.eclipse.aether.version.Version;
/**
* Uses Aether as the Maven dependency manager.
*/
public class DependencyManager {
/*
* see http://git.eclipse.org/c/aether/aether-ant.git/tree/src/main/java/org/eclipse/aether/internal/ant/AntRepoSys.java
*/
//<editor-fold desc="Constants">
/////////// Constants ///////////////////////////////////
private static final String PROP_OFFLINE = "capsule.offline";
private static final String PROP_CONNECT_TIMEOUT = "capsule.connect.timeout";
private static final String PROP_REQUEST_TIMEOUT = "capsule.request.timeout";
private static final String PROP_USER_HOME = "user.home";
private static final String ENV_CONNECT_TIMEOUT = "CAPSULE_CONNECT_TIMEOUT";
private static final String ENV_REQUEST_TIMEOUT = "CAPSULE_REQUEST_TIMEOUT";
static final Path DEFAULT_LOCAL_MAVEN = Paths.get(System.getProperty(PROP_USER_HOME), ".m2");
private static final String LATEST_VERSION = "[0,)";
public static final int LOG_NONE = 0;
public static final int LOG_QUIET = 1;
public static final int LOG_VERBOSE = 2;
public static final int LOG_DEBUG = 3;
private static final String LOG_PREFIX = "CAPSULE: ";
private static final MavenUserSettings MVN_SETTINGS = MavenUserSettings.getInstance();
static final Map<String, String> WELL_KNOWN_REPOS = unmodifiableMap(new HashMap<String, String>() {
{
put("central", "central(https://repo1.maven.org/maven2/)");
put("central-http", "central(http://repo1.maven.org/maven2/)");
put("jcenter", "jcenter(https://jcenter.bintray.com/)");
put("jcenter-http", "jcenter(http://jcenter.bintray.com/)");
put("local", "local(file:" + MVN_SETTINGS.getRepositoryHome() + ")");
}
});
//</editor-fold>
private final boolean forceRefresh;
private final boolean offline;
protected final RepositorySystem system;
private final LocalRepository localRepo;
private RepositorySystemSession session;
private List<RemoteRepository> repos;
private List<Dependency> managedDependencies;
private final int logLevel;
//<editor-fold desc="Construction and Setup">
/////////// Construction and Setup ///////////////////////////////////
public DependencyManager(Path localRepoPath, boolean forceRefresh, int logLevel) {
this.logLevel = logLevel;
this.forceRefresh = forceRefresh;
this.offline = isPropertySet(PROP_OFFLINE, false);
if (localRepoPath == null)
localRepoPath = MVN_SETTINGS.getRepositoryHome();
log(LOG_DEBUG, "DependencyManager - Offline: " + offline);
log(LOG_DEBUG, "DependencyManager - Local repo: " + localRepoPath);
this.localRepo = new LocalRepository(localRepoPath.toFile());
this.system = newRepositorySystem();
}
public final DependencyManager setRepositories(List<String> repos, boolean allowSnapshots) {
if (repos == null)
//noinspection ArraysAsListWithZeroOrOneArgument
repos = Arrays.asList("central");
final List<RemoteRepository> rs = new ArrayList<>();
for (String r : repos) {
RemoteRepository repo = createRepo(r, allowSnapshots);
if (!rs.contains(repo))
rs.add(repo);
}
if (!Objects.equals(this.repos, rs)) {
this.repos = rs;
log(LOG_VERBOSE, "Dependency manager repositories: " + this.repos);
}
return this;
}
public final DependencyManager setManagedDependencies(List<String> managedDependencies) {
this.managedDependencies = toManagedDependencies(managedDependencies);
return this;
}
/** @noinspection UnusedParameters*/
private RepositoryPolicy makeReleasePolicy(String repo) {
return new RepositoryPolicy(true, RepositoryPolicy.UPDATE_POLICY_NEVER, RepositoryPolicy.CHECKSUM_POLICY_WARN);
}
private RepositoryPolicy makeSnapshotPolicy(String repo) {
return makeReleasePolicy(repo);
}
private static RepositorySystem newRepositorySystem() {
/*
* We're using DefaultServiceLocator rather than Guice/Sisu because it's more lightweight.
* This method pulls together the necessary Aether components and plugins.
*/
final DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator();
locator.setErrorHandler(new DefaultServiceLocator.ErrorHandler() {
@Override
public void serviceCreationFailed(Class<?> type, Class<?> impl, Throwable ex) {
throw new RuntimeException("Service creation failed for type " + type.getName() + " with impl " + impl, ex);
}
});
locator.addService(org.eclipse.aether.spi.connector.RepositoryConnectorFactory.class, org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory.class);
locator.addService(org.eclipse.aether.spi.connector.transport.TransporterFactory.class, org.eclipse.aether.transport.http.HttpTransporterFactory.class);
locator.addService(org.eclipse.aether.spi.connector.transport.TransporterFactory.class, org.eclipse.aether.transport.file.FileTransporterFactory.class);
// Takari (support concurrent downloads)
locator.setService(org.eclipse.aether.impl.SyncContextFactory.class, LockingSyncContextFactory.class);
locator.setService(org.eclipse.aether.spi.io.FileProcessor.class, LockingFileProcessor.class);
return locator.getService(RepositorySystem.class);
}
private RepositorySystemSession getSession() {
if (session == null)
session = newRepositorySession(system, localRepo);
return session;
}
private RepositorySystemSession newRepositorySession(RepositorySystem system, LocalRepository localRepo) {
final DefaultRepositorySystemSession s = MavenRepositorySystemUtils.newSession();
s.setConfigProperty(ConfigurationProperties.CONNECT_TIMEOUT, propertyOrEnv(PROP_CONNECT_TIMEOUT, ENV_CONNECT_TIMEOUT));
s.setConfigProperty(ConfigurationProperties.REQUEST_TIMEOUT, propertyOrEnv(PROP_REQUEST_TIMEOUT, ENV_REQUEST_TIMEOUT));
// WARN: `ConflictResolver.CONFIG_PROP_VERBOSE` will retain (and mark) dependency graph duplicates such as conflict resolution losers since
// http://git.eclipse.org/c/aether/aether-core.git/diff/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/ConflictResolver.java?id=141a3669d23ab67846b0c3ccef14eb0cdc70cee9
s.setConfigProperty(ConflictResolver.CONFIG_PROP_VERBOSE, true);
s.setOffline(offline);
s.setUpdatePolicy(forceRefresh ? RepositoryPolicy.UPDATE_POLICY_ALWAYS : RepositoryPolicy.UPDATE_POLICY_NEVER);
s.setLocalRepositoryManager(system.newLocalRepositoryManager(s, localRepo));
s.setMirrorSelector(MVN_SETTINGS.getMirrorSelector());
s.setAuthenticationSelector(MVN_SETTINGS.getAuthSelector());
final SystemProxySelector sysProxySelector; // proxy from environment variables
s.setProxySelector((sysProxySelector = new SystemProxySelector(this)).isValid() ? sysProxySelector : MVN_SETTINGS.getProxySelector());
// no need for these, as they're set by MavenRepositorySystemUtils.newSession()
// s.setDependencyManager(newDependencyManager());
// s.setDependencySelector(newDependencySelector());
// s.setDependencyGraphTransformer(newConflictResolver());
if (logLevel > LOG_NONE) {
final PrintStream out = prefixStream(System.err, LOG_PREFIX);
s.setTransferListener(new ConsoleTransferListener(isLogging(LOG_VERBOSE), out));
s.setRepositoryListener(new ConsoleRepositoryListener(isLogging(LOG_VERBOSE), out));
}
return s;
}
// private static org.eclipse.aether.collection.DependencyManager newDependencyManager() {
// return new org.eclipse.aether.util.graph.manager.ClassicDependencyManager();
// }
// private static DependencySelector newDependencySelector() {
// return new org.eclipse.aether.util.graph.selector.AndDependencySelector(
// new org.eclipse.aether.util.graph.selector.ScopeDependencySelector(null, Arrays.asList(JavaScopes.TEST, JavaScopes.PROVIDED)),
// new org.eclipse.aether.util.graph.selector.OptionalDependencySelector(),
// new org.eclipse.aether.util.graph.selector.ExclusionDependencySelector()
// );
// }
// private static ConflictResolver newConflictResolver() {
// return new ConflictResolver(
// new org.eclipse.aether.util.graph.transformer.NearestVersionSelector(),
// new org.eclipse.aether.util.graph.transformer.JavaScopeSelector(),
// new org.eclipse.aether.util.graph.transformer.SimpleOptionalitySelector(),
// new org.eclipse.aether.util.graph.transformer.JavaScopeDeriver()
// );
// }
/** @noinspection unused*/
public void setSystemProperties(Map<String, String> properties) {
final Map<String, String> ps = Collections.unmodifiableMap(properties);
if (getSession() instanceof DefaultRepositorySystemSession)
((DefaultRepositorySystemSession) getSession()).setSystemProperties(ps);
else {
final RepositorySystemSession s = getSession();
this.session = new AbstractForwardingRepositorySystemSession() {
@Override
protected RepositorySystemSession getSession() {
return s;
}
@Override
public Map<String, String> getSystemProperties() {
return ps;
}
};
}
}
private RemoteRepository createRepo(String repo, boolean allowSnapshots) {
final RemoteRepository.Builder builder = createRepoBuilder(repo);
setPolicies(builder, allowSnapshots);
setProxy(builder);
setAuthentication(builder);
return builder.build();
}
private static final Pattern PAT_REPO = Pattern.compile("(?<id>[^(]+)(\\((?<url>[^\\)]+)\\))?");
// visible for testing
static RemoteRepository.Builder createRepoBuilder(String repo) {
final Matcher m = PAT_REPO.matcher(repo);
if (!m.matches())
throw new IllegalArgumentException("Could not parse repository: " + repo);
final String id = m.group("id");
String url = m.group("url");
if (url == null && WELL_KNOWN_REPOS.containsKey(id))
return createRepoBuilder(WELL_KNOWN_REPOS.get(id));
if (url == null)
url = id;
return new RemoteRepository.Builder(id, "default", url);
}
private RemoteRepository.Builder setPolicies(RemoteRepository.Builder builder, boolean allowSnapshots) {
final RemoteRepository tmp = builder.build(); // cheap operation
final String id = tmp.getId();
final String url = tmp.getUrl();
RepositoryPolicy releasePolicy = makeReleasePolicy(id);
RepositoryPolicy snapshotPolicy = allowSnapshots ? makeSnapshotPolicy(id) : new RepositoryPolicy(false, null, null);
if (url.startsWith("file:")) {
releasePolicy = new RepositoryPolicy(releasePolicy.isEnabled(), releasePolicy.getUpdatePolicy(), RepositoryPolicy.CHECKSUM_POLICY_IGNORE);
snapshotPolicy = releasePolicy;
}
builder.setReleasePolicy(releasePolicy)
.setSnapshotPolicy(snapshotPolicy);
return builder;
}
private RemoteRepository.Builder setProxy(RemoteRepository.Builder builder) {
final RemoteRepository tmp = builder.build(); // cheap operation
final ProxySelector selector = getSession().getProxySelector();
final Proxy proxy = selector.getProxy(tmp);
if (proxy != null) {
if (isLogging(LOG_DEBUG))
log(LOG_DEBUG, String.format("Setting proxy: '%s' for dependency repo: %s", proxy, tmp.toString()));
builder.setProxy(proxy);
}
return builder;
}
private RemoteRepository.Builder setAuthentication(RemoteRepository.Builder builder) {
final RemoteRepository tmp = builder.build(); // cheap operation
final AuthenticationSelector authenticationSelector = getSession().getAuthenticationSelector();
final Authentication authentication = authenticationSelector.getAuthentication(tmp);
if (authentication != null) {
if (isLogging(LOG_DEBUG))
log(LOG_DEBUG, String.format("Setting authentication for dependency repo: %s", tmp.toString()));
builder.setAuthentication(authentication);
}
return builder;
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="Operations">
/////////// Operations ///////////////////////////////////
private CollectRequest collect() {
return new CollectRequest().setRepositories(repos).setManagedDependencies(managedDependencies);
}
public final void printDependencyTree(List<String> coords, String type, PrintStream out) {
printDependencyTree(toDependencies(coords, type), out);
}
public final void printDependencyTree(List<Dependency> deps, PrintStream out) {
printDependencyTree(collect().setDependencies(deps), out);
}
public final void printDependencyTree(String coords, String type, PrintStream out) {
printDependencyTree(collect().setRoot(toDependency(coords, type)), out);
}
private void printDependencyTree(CollectRequest collectRequest, PrintStream out) {
try {
CollectResult collectResult = system.collectDependencies(getSession(), collectRequest);
collectResult.getRoot().accept(new ConsoleDependencyGraphDumper(out));
} catch (DependencyCollectionException e) {
throw new RuntimeException(e);
}
}
public final List<Path> resolveDependencies(List<String> coords, String type) {
return resolve(collect().setDependencies(toDependencies(coords, type)));
}
public final List<Path> resolveDependency(String coords, String type) {
return resolve(collect().setRoot(toDependency(coords, type))); // resolveDependencies(Collections.singletonList(coords), type);
}
public final Map<Dependency, List<Path>> resolveDependencies(List<Dependency> deps) {
final List<DependencyNode> children = resolve0(collect().setDependencies(deps)).getRoot().getChildren();
final Map<Dependency, List<Path>> resolved = new HashMap<>();
for (DependencyNode dn : children) {
final List<Path> jars = new ArrayList<>();
resolved.put(clean(dn.getDependency()), jars);
dn.accept(new DependencyVisitor() {
@Override
public final boolean visitEnter(DependencyNode node) {
if (!isLoser(node))
jars.add(path(node.getArtifact()));
return true;
}
@Override
public final boolean visitLeave(DependencyNode node) {
return true;
}
});
}
return resolved;
}
private List<Path> resolve(CollectRequest collectRequest) {
final List<Path> jars = new ArrayList<>();
for (ArtifactResult artifactResult : resolve0(collectRequest).getArtifactResults())
jars.add(path(artifactResult.getArtifact()));
return jars;
}
private DependencyResult resolve0(CollectRequest collectRequest) {
if (isLogging(LOG_DEBUG))
log(LOG_DEBUG, "DependencyManager.resolve " + collectRequest);
try {
final DependencyRequest dependencyRequest = new DependencyRequest(collectRequest,
new DependencyFilter() {
@Override
public boolean accept(DependencyNode n, List<DependencyNode> parents) {
// Exclude conflict losers (which are marked but left in if verbose mode is enabled, see
// http://git.eclipse.org/c/aether/aether-core.git/diff/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/ConflictResolver.java?id=141a3669d23ab67846b0c3ccef14eb0cdc70cee9t
return !isLoser(n);
}
});
final DependencyResult result = system.resolveDependencies(getSession(), dependencyRequest);
if (isLogging(LOG_DEBUG))
log(LOG_DEBUG, "DependencyManager.resolve: " + result);
return result;
} catch (DependencyResolutionException e) {
throw new RuntimeException("Error resolving dependencies.", e);
}
}
public final String getLatestVersion(String coords, String type) {
return artifactToCoords(getLatestVersion0(coords, type));
}
protected Artifact getLatestVersion0(String coords, String type) {
try {
final Artifact artifact = coordsToArtifact(coords, type);
final String version;
if (isVersionRange(artifact.getVersion())) {
final VersionRangeRequest request = new VersionRangeRequest().setRepositories(repos).setArtifact(artifact);
final VersionRangeResult result = system.resolveVersionRange(getSession(), request);
final Version highestVersion = result.getHighestVersion();
version = highestVersion != null ? highestVersion.toString() : null;
} else {
final VersionRequest request = new VersionRequest().setRepositories(repos).setArtifact(artifact);
final VersionResult result = system.resolveVersion(getSession(), request);
version = result.getVersion();
}
if (version == null)
throw new RuntimeException("Could not find any version of artifact " + coords + " (looking for: " + artifact + ")");
return artifact.setVersion(version);
} catch (RepositoryException e) {
throw new RuntimeException(e);
}
}
private static Path path(Artifact artifact) {
return artifact.getFile().toPath().toAbsolutePath();
}
private boolean isLoser(DependencyNode dn) {
final DependencyNode winner = (DependencyNode) dn.getData().get(ConflictResolver.NODE_DATA_WINNER);
return winner != null && !ArtifactIdUtils.equalsId(dn.getArtifact(), winner.getArtifact());
}
private Dependency clean(Dependency d) {
// necessary for dependency equality
// SNAPSHOT dependencies get resolved to specific artifacts, so returned dependency is different from original
final Artifact a = d.getArtifact();
return new Dependency(new DefaultArtifact(a.getGroupId(), a.getArtifactId(), a.getClassifier(), a.getExtension(), a.getBaseVersion()),
d.getScope(), d.getOptional(), d.getExclusions());
}
private boolean equalExceptVersion(Artifact a, Artifact b) {
return Objects.equals(a.getGroupId(), b.getGroupId())
&& Objects.equals(a.getArtifactId(), b.getArtifactId())
&& Objects.equals(a.getExtension(), b.getExtension())
&& Objects.equals(a.getClassifier(), b.getClassifier())
&& Objects.equals(a.getBaseVersion(), b.getBaseVersion());
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="Parsing">
/////////// Parsing ///////////////////////////////////
public static Dependency toDependency(String coords, String type) {
return new Dependency(coordsToArtifact(coords, type), JavaScopes.RUNTIME, false, getExclusions(coords));
}
private static List<Dependency> toDependencies(List<String> coords, String type) {
final List<Dependency> deps = new ArrayList<>(coords.size());
for (String c : coords)
deps.add(toDependency(c, type));
return deps;
}
static String artifactToCoords(Artifact artifact) {
if (artifact == null)
return null;
return artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion()
+ ((artifact.getClassifier() != null && !artifact.getClassifier().isEmpty()) ? (":" + artifact.getClassifier()) : "");
}
private static boolean isVersionRange(String version) {
return version.startsWith("(") || version.startsWith("[");
}
private static final Pattern PAT_DEPENDENCY = Pattern.compile("(?<groupId>[^:\\(]+):(?<artifactId>[^:\\(]+)(:(?<version>\\(?[^:\\(]*))?(:(?<classifier>[^:\\(]+))?(\\((?<exclusions>[^\\(\\)]*)\\))?");
private static Artifact coordsToArtifact(String depString, String type) {
final Matcher m = PAT_DEPENDENCY.matcher(depString);
if (!m.matches())
throw new IllegalArgumentException("Could not parse dependency: " + depString);
final String groupId = m.group("groupId");
final String artifactId = m.group("artifactId");
final String version = emptyToNull(m.group("version"));
final String classifier = m.group("classifier");
return new DefaultArtifact(groupId, artifactId, classifier, type, version);
}
private static Collection<Exclusion> getExclusions(String depString) {
final Matcher m = PAT_DEPENDENCY.matcher(depString);
if (!m.matches())
throw new IllegalArgumentException("Could not parse dependency: " + depString);
if (m.group("exclusions") == null || m.group("exclusions").isEmpty())
return null;
final List<String> exclusionPatterns = Arrays.asList(m.group("exclusions").split(","));
final List<Exclusion> exclusions = new ArrayList<>();
for (String ex : exclusionPatterns) {
String[] coords = ex.trim().split(":");
if (coords.length != 2)
throw new IllegalArgumentException("Illegal exclusion dependency coordinates: " + depString + " (in exclusion " + ex + ")");
exclusions.add(new Exclusion(coords[0], coords[1], "*", "*"));
}
return exclusions;
}
protected static List<Dependency> toManagedDependencies(List<String> coords) {
final List<Dependency> deps = new ArrayList<>(coords.size());
for (String c : coords)
deps.add(toManagedDependency(c));
return deps;
}
private static final Pattern PAT_DEPENDENCY_MANAGEMENT = Pattern.compile("(?<groupId>[^:\\(]+):(?<artifactId>[^:\\(]+):(?<type>[^:\\(]*):(?<classifier>[^:\\(]*):(?<version>\\(?[^:\\(]+)");
static Dependency toManagedDependency(String depString) {
final Matcher m = PAT_DEPENDENCY_MANAGEMENT.matcher(depString);
if (!m.matches())
throw new IllegalArgumentException("Could not parse dependency management: " + depString);
final String groupId = m.group("groupId");
final String artifactId = m.group("artifactId");
final String type = emptyToNull(m.group("type"));
final String classifier = emptyToNull(m.group("classifier"));
String version = emptyToNull(m.group("version"));
if (version == null)
throw new IllegalArgumentException("No version information is provided for managed dependency " + depString);
boolean optional = false;
if ("-".equals(version)) {
version = null;
optional = true;
}
final Artifact artifact = new DefaultArtifact(groupId, artifactId, classifier, type, version);
return new Dependency(artifact, JavaScopes.RUNTIME, optional);
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="General Utils">
/////////// General Utils ///////////////////////////////////
private static PrintStream prefixStream(PrintStream out, final String prefix) {
return new PrintStream(out) {
@Override
public void println(String x) {
super.println(prefix + x);
}
};
}
private static boolean hasArtifactPath(DependencyNode node) {
Artifact a;
return node != null
&& (a = node.getArtifact()) != null
&& a.getFile() != null;
}
private static String propertyOrEnv(String propName, String envVar) {
String val = System.getProperty(propName);
if (val == null)
val = emptyToNull(System.getenv(envVar));
return val;
}
private static Boolean isPropertySet(String property, boolean defaultValue) {
final String val = System.getProperty(property);
if (val == null)
return defaultValue;
return "".equals(val) | Boolean.parseBoolean(val);
}
static String emptyToNull(String s) {
if (s == null)
return null;
s = s.trim();
return s.isEmpty() ? null : s;
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="Logging">
/////////// Logging ///////////////////////////////////
final boolean isLogging(int level) {
return level <= logLevel;
}
final void log(int level, String str) {
if (isLogging(level))
System.err.println(LOG_PREFIX + str);
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="DI Workarounds">
/////////// DI Workarounds ///////////////////////////////////
// necessary if we want to forgo Guice/Sisu injection and use DefaultServiceLocator instead
private static final io.takari.filemanager.FileManager takariFileManager = new io.takari.filemanager.internal.DefaultFileManager();
public static class LockingFileProcessor extends io.takari.aether.concurrency.LockingFileProcessor {
public LockingFileProcessor() {
super(takariFileManager);
}
}
public static class LockingSyncContextFactory extends io.takari.aether.concurrency.LockingSyncContextFactory {
public LockingSyncContextFactory() {
super(takariFileManager);
}
}
//</editor-fold>
}